﻿using System;
using System.Linq;
using CCodeTreeLib;
using SqlOrm.Xml;
using System.Collections.Generic;

namespace SqlOrm.TreeBuilders
{
    public class EntitiesTreeBuilder : CCodeTree
    {
        DataDictionary _ddl;

        public EntitiesTreeBuilder(DataDictionary ddl)
        {
            _ddl = ddl;
            Build();
        }

        public void Build()
        {
            BuildEntities();
        }

        private void BuildEntities()
        {
            Console.WriteLine("Building entities...");
            this.Usings.Add(new CCodeUsing("System"));
            var ns = AddStatement(new CCodeNamespace(_ddl.Settings.EntitiesOutput.clrnamespace));
            foreach (var table in _ddl.Definition.Schema.Table)
            {
                var enumFields = table.Field.Where(x => !string.IsNullOrEmpty(x.EnumName));
                foreach (var f in enumFields)
                {
                    var cEnum = new CCodeEnum(string.Format("{0}{1}", table.ClassName, f.title));
                    int count = 1;
                    foreach (var e in f.Enum)
                    {
                        string sval = count.ToString();
                        if (!string.IsNullOrEmpty(e.value))
                            sval = e.value;
                        cEnum.Values.Add(new CCodeAssign(e.desc, sval));
                        ++count;
                    }
                    Console.WriteLine("Enum: " + cEnum.Name);
                    ns.AddStatement(cEnum);
                }
            }
            if (_ddl.Definition.Schema != null)
            {
                foreach (var table in _ddl.Definition.Schema.Table)
                {
                    var cls = new CCodeClass(table.ClassName) { Modifier = Modifier.Public };
                    foreach (var f in table.Field)
                        cls.AddMember(new CCodeProperty(!string.IsNullOrEmpty(f.title) ? f.title : f.name, f.ClrDataType));
                    //Console.WriteLine("Entity: " + cls.Name);
                    ns.AddStatement(cls);
                }
            }
            if (_ddl.Definition.Procedures != null)
            {
                foreach (var proc in _ddl.Definition.Procedures)
                {
                    var nfGroupedByTypeName = proc.NestedFields.GroupBy(x => x, n => n.Field, (k, f) => new { Key = k, Fields = f }, new NestedFieldComparer()).Where(x => x.Key.NestedClassName != null);
                    if (nfGroupedByTypeName.Count() > 0)
                    {
                        foreach (var g in nfGroupedByTypeName)
                        {
                            if (!_ddl.Definition.Schema.Table.Any(x => x.ClassName == g.Key.NestedType))
                            {
                                var cls = new CCodeClass(g.Key.NestedType);
                                cls.Modifier = Modifier.Public;
                                foreach (var f in g.Fields)
                                    cls.AddMember(new CCodeProperty(!string.IsNullOrEmpty(f.title) ? f.title : f.name, f.ClrDataType));
                                ns.AddStatement(cls);
                            }
                        }
                    }
                    if (proc.OutputType == ProcedureOutputType.Custom)
                    {
                        var cls = new CCodeClass(proc.name + "Output");
                        cls.Modifier = Modifier.Public;
                        foreach (var f in proc.NestedFields.Where(x=>x.NestedClassName==null).Select(x=>x.Field))
                            cls.AddMember(new CCodeProperty(!string.IsNullOrEmpty(f.title) ? f.title : f.name, f.ClrDataType));
                        foreach (var g in nfGroupedByTypeName)
                            cls.AddMember(new CCodeProperty(g.Key.NestedClassName, g.Key.NestedType));
                        //Console.WriteLine("Entity: " + cls.Name);
                        ns.AddStatement(cls);
                    }
                }
            }
        }
    }
}
